package com.basic.common.aspect;



import com.basic.common.utils.ParamsModel;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.Objects;

/**
 * Created by rwh on 2024/8/17 8:44
 */
@Component
@Aspect
public class StringTrimAspect {
    @Pointcut(value = "@annotation(com.basic.common.annotation.StringTrim)")
    public void trim(){

    }

    @Before("trim()")
    public Object before(JoinPoint joinpoint) throws IllegalAccessException, NoSuchFieldException {
        // joinpoint表示什么：joinpoint加在什么地方，就表示什么。比如加在方法上，他就表示这个方法，里面的东西包括该方法的方法名，该方法
        // 所在的类，所在的位置，该方法的参数等等
        System.out.println("去除字符串前后空格start");
        // 获取方法参数
        Object[] args = joinpoint.getArgs();
        if (Objects.nonNull(args)&&args.length>0) {
            // 处理接口传参，去除首尾空格
            for (int i = 0; i < args.length; i++) {
                args[i]=trimExe(args[i]);
            }
        }
        return args;
    }

    private Object trimExe(Object arg) throws IllegalAccessException, NoSuchFieldException {
        // 对象为空，不处理
        if (Objects.isNull(arg)) {
            return arg;
        }
        // 获取对象的类型
        Class<?> clazz = arg.getClass();
        // 处理string类型数据
        if (clazz==String.class) {
            // 如果直接用：return arg.toString().trim();会导致生成一个新的string对象，
            // 这个新的对象去除空格了，但是原来的对象还是没有去除空格。可以用get方式测试

            // 修改string参数的值，不改变它的地址值（引用）
            String trim = arg.toString().trim();
            Field value = arg.getClass().getDeclaredField("value");
            value.setAccessible(true);
            value.set(arg,trim.toCharArray());
            return arg;
        } else if (clazz== ParamsModel.class) {
            Object condition = ((ParamsModel<?>) arg).getCondition();
            return trimExe(condition);
        }
        // 处理 对象类型数据，对象里可能有string类型字段
        Field[] fields = clazz.getDeclaredFields(); // 获取类的字段
        if (Objects.isNull(fields)||fields.length==0) {
            return arg;
        }
        for (Field field : fields) {
            field.setAccessible(true); // 如果是private时，意为允许访问该字段
            Class<?> fieldType = field.getType(); // 获取该字段的类型

            // 只处理string类型
            if (fieldType!=String.class) {
                continue;
            }

            // 获取该字段的值
            Object o = field.get(arg);
            if (Objects.nonNull(o)) {
                // 在原有的基础上 设置 去除前后空格的新值
                field.set(arg,String.valueOf(o).trim()); // 第一个参数是该对象的实例，第二个参数是要设置的值
            }

        }
        return arg;
    }
}